package org.calzz.jajb;

import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.calzz.jajb.converter.BeanConverter;
import org.calzz.jajb.converter.IConverter;
import org.calzz.jajb.io.IReader;
import org.springframework.core.MethodParameter;

/**
 * Deserializer of JSON objects into Java beans. Uses a given implementation of
 * the <code>IReader</code> interface for parsing input string into object
 * environment.
 * 
 * @author Marek Brodziak <marek.brodziak@gmail.com>
 * @author Piotr Pejas <piotr.pejas@gmail.com>
 * @since Feb 10, 2008
 */
public class JsonDeserializer {

	private Set<IConverter> converters = new HashSet<IConverter>();
	private IReader reader;

	/**
	 * Default contructor for this deserializer.
	 * @param reader <code>IReader</code> interface implementation
	 */
	public JsonDeserializer(IReader reader) {
		this.reader = reader;
	}

	/**
	 * Processes a given object and deserializes it into a Java object of a
	 * given type.
	 * @param env object to be deserialized taken from the <code>IReader</code>
	 * @param clazz type of this object
	 * @return deserialized Java object
	 */
	public Object process(Object env, Class<?> clazz, MethodParameter methodParam) {

		if (env == null) {
			return null;
		}

		for (IConverter converter : converters) {
			if (converter.canConvert(clazz)) {
				return converter.unmarshal(env, clazz, this, methodParam);
			}
		}

		return new BeanConverter().unmarshal(env, clazz, this, methodParam);
	}

	/**
	 * Main method used for deserializing a given JSON string into a Java object
	 * of a given type.
	 * @param <T> type of the object
	 * @param json JSON-formatted <code>String</code>
	 * @param clazz class of the object
	 * @return deserialized object
	 */
	@SuppressWarnings("unchecked")
	public <T> T deserialize(String json, Class<T> clazz) {
		Map<String, Object> tokens = reader.deserialize(json);
		return (T) process(tokens, clazz, null);
	}

	/**
	 * Sets a collection of converters used by this deserializer. Method to be
	 * used with Spring framework.
	 * @param converters set of converters for the serializer
	 */
	public void setConverters(Set<IConverter> converters) {
		this.converters = converters;
	}

	/**
	 * Registers a single converter in the deserializer environment.
	 * @param converter converter to be registered
	 */
	public void registerConverter(IConverter converter) {
		this.converters.add(converter);
	}

}
